home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Risc World 3
/
Risc World 3.iso
/
SOFTWARE
/
ISSUE6
/
PD
/
PDF
/
pdf
/
c++
/
Printer
< prev
next >
Wrap
Text File
|
2003-02-14
|
19KB
|
652 lines
//--------------------------------------------------------------------------
//
// Copyright (c) 2002, Colin Granville
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the following
// conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// * The name Colin Granville may not be used to endorse or promote
// products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//--------------------------------------------------------------------------
#include "Printer.h"
#include "Document.h"
#include "GuiTargets.h"
#include "GuiWimpMessage.h"
#include "GuiWindow.h"
#include "GuiGadget.h"
#include "GuiTask.h"
#include "guilib:gfx.h"
#include "guilib:ERROR.h"
#include "DrawOutputDevice.h"
#include "iostream.h"
#include "GuiHourGlass.h"
#include "UserEvents.h"
class PrintJob
{
public:
PrintJob(const char* filename,const char* title=0);
~PrintJob();
void abort();
operator void*() {return job?this:0;}
int operator!() {return !job;}
private:
void close() {if (job) {_swix(OS_Find,_INR(0,1),0,job);job=0;}}
int job;
int oldJob;
};
//*************************************************************************
PrintJob::PrintJob(const char* filename,const char* title)
: job(0),
oldJob(0)
{
if (_swix(OS_Find,_INR(0,1) | _OUT(0),0x8f,filename,&job) == 0 &&
_swix(PDriver_SelectJob,_INR(0,1) | _OUT(0),job,title,&oldJob)==0) return;
close();
}
//*************************************************************************
PrintJob::~PrintJob()
{
if (!job) return;
_swix(PDriver_EndJob,_IN(0),job);
_swix(PDriver_SelectJob,_INR(0,1),oldJob,0);
close();
}
//*************************************************************************
void PrintJob::abort()
{
if (!job) return;
_swix(PDriver_AbortJob,_IN(0),job);
_swix(PDriver_SelectJob,_INR(0,1),oldJob,0);
close();
}
//*************************************************************************
//*************************************************************************
//*************************************************************************
class PrintArea
{
public:
enum {FULL_PAGE,TOP_HALF,BOTTOM_HALF};
PrintArea(Document& document,int page,int page_type,bool side2,const DocViewChoices&,bool isLandscape);
_kernel_oserror* render(int id,GuiBBox& bounds);
private:
int id;
DrawOutputDevice outDev;
GuiTransform trfm;
bool isBlank;
};
//*************************************************************************
int nextId()
{
static int n=1;
n^=1;
return n;
}
PrintArea::PrintArea(Document& document,int page,int page_type, bool side2,
const DocViewChoices& viewChoices,bool isLandscape)
: id(nextId()),
isBlank(page<=0)
{
if (page<0) return;
int paper_width,paper_height;
if (_swix(PDriver_PageSize,_OUTR(1,2),&paper_width,&paper_height)) return;
if (page_type != FULL_PAGE) paper_height/=2;
int y_offset=(page_type==TOP_HALF ? paper_height : 0);
GuiBBox bounds;
if (page > 0)
{
outDev.setMoreColours(gTrue);
outDev.setNoImages(viewChoices.getNoImages());
outDev.setNoText(viewChoices.getNoText());
outDev.setNoImages(viewChoices.getNoDrawings());
outDev.setNoText(viewChoices.getNoType3Fonts());
int rotation=0;
if (page_type != FULL_PAGE ||
(isLandscape && page_type == FULL_PAGE) ) rotation=(side2 ? 90 : 270);
document.getPage(page,&outDev,DrawOutputDevice::DPI,rotation);
trfm.m0 = (1<<16);//1.08b9 (page_type == FULL_PAGE ? (1<<16) : 46341);// (1/root2)
trfm.m1 = 0;
trfm.m2 = 0; trfm.m3 = trfm.m0;
trfm.m4 = 0; trfm.m5 = 0;
outDev.getDrawFile().getBBox(bounds,&trfm);
int wid=bounds.getWidth()*25/16; //convert to millipoints
int ht =bounds.getHeight()*25/16;
if (wid>paper_width || ht>paper_height)
{
double scale = (double)paper_width/(double)wid;
double yscale= (double)paper_height/(double)ht;
if (scale>yscale) scale=yscale;
trfm.m0 = (int)((double)trfm.m0*scale);
trfm.m3 = (int)((double)trfm.m3*scale);
wid=(int)((double)wid*scale);
ht=(int)((double)ht*scale);
}
trfm.m4=((paper_width-wid)/2)*16/25;
trfm.m5=((paper_height-ht)/2+y_offset)*16/25;
}
bounds(0,y_offset/400,paper_width/400,(paper_height+y_offset)/400);
int printer_trfm[4];
printer_trfm[0]=(1<<16); printer_trfm[1]=0;
printer_trfm[2]=0; printer_trfm[3]=printer_trfm[0];
int origin[2];
origin[0]=0;
origin[1]=y_offset;
_swix(PDriver_GiveRectangle,_INR(0,4),id,&bounds,printer_trfm,origin,0xFFFFFF00);
}
//*************************************************************************
_kernel_oserror* PrintArea::render(int id_, GuiBBox& bounds)
{
if (id!=id_ || isBlank) return 0;
return outDev.getDrawFile().render(&trfm,&bounds,0);
}
//*************************************************************************
//*************************************************************************
//*************************************************************************
class PrinterProxy : public Node
{
public:
virtual ~PrinterProxy();
DECLARE_RTTI();
};
//*************************************************************************
//*************************************************************************
//*************************************************************************
PrintData::PrintData()
: document(0),
copies(1),
flags(0),
from(1),
to(1),
start(0),
end(0),
sectionSize(0)
{
}
//*************************************************************************
//*************************************************************************
//*************************************************************************
class Printer
{
public:
friend Printer& printer();
bool print(const PrintData&);
void release() {claimed=0;} //called by PrinterProxy when it is deleted
private:
Node* claimed;
int myRef;
GuiWindow mainWin;
GuiActionButton continueButton;
GuiActionButton cancelButton;
GuiButton statusText;
PrintData data;
Printer();
~Printer();
void finished();
_kernel_oserror* printOneSide();
_kernel_oserror* printSide(int page,int bottom_page,bool turn_clockwise);
void startPrinting();
GUI_DECLARE_EVENT_TARGETS(Printer);
GuiToolboxTarget printSide2Target;
Claim printSide2(GuiToolboxEvent&,const GuiIdBlock&);
GuiWimpTarget protocolBounced;
Claim noPrinter(GuiWimpPollBlock&, const GuiIdBlock&);
GuiMessageTarget protocolA;
Claim printFile(GuiWimpMessage&);
Claim printTypeOdd(GuiWimpMessage&);
GuiMessageTarget protocolB;
Claim printError(GuiWimpMessage&);
Claim dataSaveAck(GuiWimpMessage&);
GuiNullTarget nullEvent;
void startProtocol();
};
//*************************************************************************
Printer::Printer()
: claimed(0),
mainWin("printStatus"),
continueButton(mainWin,0),
cancelButton(mainWin,2),
statusText(mainWin,1),
printSide2Target(&mainWin,User_PrintSide2,this,Printer::printSide2)
{
}
//*************************************************************************
Printer::~Printer() {}
//*************************************************************************
inline void set_short(char*& buf,int i)
{
*buf++=(i & 0xff);
*buf++=((i>>8) & 0xff);
}
static void set_mouse_rectangle(const GuiBBox* box=0)
{
char buf[16];
char*b=buf;
*b++=1;
set_short(b,(box ? box->xmin : 0));
set_short(b,(box ? box->ymin : 0));
set_short(b,(box ? box->xmax : gfx::screenwidth()-1));
set_short(b,(box ? box->ymax : gfx::screenheight()-1));
_swix(OS_Word,_INR(0,1),21,buf);
}
//*************************************************************************
void Printer::finished()
{
protocolBounced.destroy();
protocolA.destroy();
protocolB.destroy();
delete claimed;
claimed=0;
mainWin.hide();
}
//*************************************************************************
bool Printer::print(const PrintData& d)
{
if (claimed) return 0;
if (!d.document) return 0;
data=d;
claimed=data.document->addChild(new PrinterProxy); //keeps document open if no views
if (!claimed) return 0;
mainWin.showCentred();
startPrinting();
return 1;
}
//*************************************************************************
void Printer::startPrinting()
{
statusText.setValue(guiTask().lookup("PRINT_ABORT:Press <Escape> to Abort"));
cancelButton.fade(1);
continueButton.fade(1);
nullEvent(this,Printer::startProtocol);
}
//*************************************************************************
void Printer::startProtocol()
{
nullEvent.destroy();
protocolBounced(0,GuiWimp_EUserMessageAcknowledge,this,Printer::noPrinter);
protocolA(GuiWimp_MPrintFile,this,Printer::printFile);
protocolB(GuiWimp_MPrintError,this,Printer::printError);
GuiWimpMessage mess;
mess.hdr.size=44;
myRef=mess.sendRecorded(GuiWimp_MPrintSave);
}
//*************************************************************************
Claim Printer::noPrinter(GuiWimpPollBlock& wpb,const GuiIdBlock&)
{
GuiWimpMessage& mess= (GuiWimpMessage&) wpb;
if (mess.hdr.myRef!=myRef) return DONT_CLAIM;
finished();
return CLAIM;
}
//*************************************************************************
Claim Printer::printError(GuiWimpMessage& mess)
{
if (mess.hdr.yourRef!=myRef) return DONT_CLAIM;
finished();
if (mess.hdr.size==20)
WARN("Printer Busy");
else
WARN((const _kernel_oserror*)&mess.data);
return CLAIM;
}
//*************************************************************************
Claim Printer::printFile(GuiWimpMessage& mess)
{
if (mess.hdr.yourRef!=myRef) return DONT_CLAIM;
protocolBounced.destroy();
protocolA(GuiWimp_MPrintTypeOdd,this,Printer::printTypeOdd);
protocolB(GuiWimp_MDataSaveAck,this,Printer::dataSaveAck);
return CLAIM;
}
//*************************************************************************
Claim Printer::printTypeOdd(GuiWimpMessage& mess)
{
if (mess.hdr.yourRef!=myRef) return DONT_CLAIM;
protocolA.destroy();
protocolB.destroy();
mess.reply(GuiWimp_MPrintTypeKnown);
GuiHourglass hourglass;
_kernel_oserror* err =printOneSide();
if (err ||
(data.flags & PrintData::IS_DOUBLE_SIDED)==0 ||
data.flags & PrintData::IS_SIDE2)
{
finished();
WARN(err);
return CLAIM;
}
GuiGetWindowStateBlock state;
mainWin.getState(state);
set_mouse_rectangle(&state.visibleArea);
statusText.setValue(guiTask().lookup("PRINT_SIDE2:Turn paper over"));
cancelButton.fade(0);
continueButton.fade(0);
gfx::vdu(7);
return CLAIM;
}
//*************************************************************************
Claim Printer::printSide2(GuiToolboxEvent&,const GuiIdBlock& id_block)
{
set_mouse_rectangle();
if (id_block.self.component!=continueButton.componentId())
{
finished();
return CLAIM;
}
data.flags |= PrintData::IS_SIDE2;
startPrinting();
return CLAIM;
}
//*************************************************************************
Claim Printer::dataSaveAck(GuiWimpMessage&)
{
finished();
WARN("Printer Busy");
return CLAIM;
}
//*************************************************************************
_kernel_oserror* Printer::printOneSide()
{
PrintJob job("printer:","PDF");
if (!job) return _kernel_last_oserror();
if (_swix(PDriver_CheckFeatures,_INR(0,1),1<<29,1<<29)==0)
{
DrawOutputFontList::declareFonts();
_swix(PDriver_DeclareFont,_INR(0,2),0,0,0);
}
int copies=data.copies;
if (copies<1 || (data.flags & PrintData::IS_COLLATE)==0) copies=1;
for (;copies;copies--)
{
int from = data.from;
if (from==0) from=1;
int to = data.to;
if (to==0) to = data.document->getPageCount();
if (data.flags & PrintData::IS_ALL)
{
from=1;
to=data.document->getPageCount();
}
if (to<from) to=from;
int number_of_sheets=to-from+1;
int step=(data.flags & PrintData::IS_REVERSES_SHEETS?-1:1);
int page=(data.flags & PrintData::IS_REVERSES_SHEETS?to:from);
int fold_total=0;
int turn_clockwise=0;
if (data.flags & PrintData::IS_DOUBLE_SIDED)
{
int section_start=1;
int section_end=data.document->getPageCount();
if (data.flags & PrintData::IS_START_END)
{
if (data.start>section_start) section_start=data.start;
if (data.end && data.end<section_end) section_end=data.end;
}
if (section_end<section_start) section_end=section_start;
if (from<section_start) from=section_start;
if (to>section_end) to=section_end;
if (to<from) to=from;
if (data.flags & PrintData::IS_PAMPHLET)
{
fold_total=((section_end-section_start)|3)+section_start*2;
int first_page=(from-section_start)&~1;
int last_page=(to-section_start)|1;
int section_size =((section_end-section_start)|3);
if (first_page>(section_size/2))
{
int n=section_size-first_page;
first_page=section_size-last_page;
last_page=n;
}
else if (last_page>(section_size/2))
{
last_page=section_size-last_page;
if (last_page<first_page) first_page=last_page;
last_page=section_size/2;
}
first_page&=~1;
last_page&=~1;
number_of_sheets=(last_page-first_page)/2 + 1;
from=first_page+section_start;
to=fold_total-from;
if (to>section_end) to=section_end;
page=last_page+section_start;
step=-2;
}
else
{
from = ((from-section_start)&~1)+section_start;
to = ((to-section_start)|1)+section_start;
number_of_sheets = (to-from+1)/2;
if (to>section_end) to=section_end;
page=((to-section_start) &~1)+section_start;
step=-2;
}
if (data.flags & PrintData::IS_SIDE2)
{
if ((data.flags & PrintData::IS_REVERSES_SHEETS)==0) {page+=1;turn_clockwise=1;}
}
else
{
if (data.flags & PrintData::IS_TURNS_PAPER_OVER) {page=from;step=2;}
if (data.flags & PrintData::IS_REVERSES_SHEETS) {page+=1;turn_clockwise=1;}
}
}
int i=0;
_kernel_oserror* err=0;
for (;i<number_of_sheets;i++)
{
int bottom_page=-1; //-1 no bottom_page, 0 blank bottom page;
if (fold_total) bottom_page=fold_total-page;
err=printSide((page>=from && page<=to ? page : 0),
(bottom_page==-1 || (bottom_page>=from && bottom_page<=to) ? bottom_page : 0),
turn_clockwise);
if (err)
{
job.abort();
return err;
}
GuiHourglass::percentage((i+1)*100/number_of_sheets);
//cerr << (page>=from && page<=to ? page : 0) << ' '
// << (bottom_page==-1 || (bottom_page>=from && bottom_page<=to) ? bottom_page : 0) << ' '
// << turn_clockwise
// << endl;
page+=step;
}
}
return 0;
}
//*************************************************************************
_kernel_oserror* Printer::printSide(int top_page,int bottom_page,bool turn_clockwise)
{
PrintArea top(*data.document,top_page,
(bottom_page<0 ? PrintArea::FULL_PAGE : PrintArea::TOP_HALF),
turn_clockwise,data.viewChoices,data.flags & PrintData::IS_LANDSCAPE);
PrintArea bottom(*data.document,bottom_page,PrintArea::BOTTOM_HALF,turn_clockwise,data.viewChoices,
data.flags & PrintData::IS_LANDSCAPE);
GuiBBox bounds;
int more=0;
int id;
_kernel_oserror* err=0;
int force_page=1;
int copies=data.copies;
if (copies <= 0 || data.flags & PrintData::IS_COLLATE) copies=1;
for (err=_swix(PDriver_DrawPage,_INR(0,3)|_OUT(0)|_OUT(2),copies,&bounds,0,0,&more,&id);
!err && more;
err=_swix(PDriver_GetRectangle,_IN(1) |_OUT(0)|_OUT(2),&bounds,&more,&id))
{
if (force_page)
{
// force blank page by making sure something is printed on it
// can't use 0xffffff00 as colour as it still thinks nothing is printed
// so put the smallest of dots on the page
static int path[]={2,0,0,8,0,1*256,0,0};
static int trfm[]={(1<<16),0,0,(1<<16),0,0};
gfx::gcol_bgr(0,0x0);
trfm[4] = (bounds.xmin+8)*256-1;
trfm[5] = (bounds.ymin+8)*256-1;
err=_swix(Draw_Stroke,_INR(0,6),path,0,trfm,0,0,0,0);
force_page=0;
}
err=top.render(id,bounds);
if (!err) err=bottom.render(id,bounds);
}
return err;
}
//*************************************************************************
//*************************************************************************
//*************************************************************************
PrinterProxy::~PrinterProxy()
{
printer().release();
}
DEFINE_RTTI_DERIVED(PrinterProxy,Node);
//*************************************************************************
//*************************************************************************
//*************************************************************************
Printer& printer()
{
static Printer p;
return p;
}
//*************************************************************************
bool Printer_print(const PrintData& data)
{
return printer().print(data);
}